package com.dongnao.network.nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * 结合Selector实现非阻塞服务器，通过Selector实现IO多路服用模型
 * @author sjy
 * @date 2024年05月10日 13:40
 */
public class MultipleIOServer {

    public static void main(String[] args) throws IOException {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);//设置为非阻塞模式
        //创建Selector
        Selector selector = Selector.open();
        //把服务端的channel注册到selector，注册accept事件
        SelectionKey selectionKey = serverSocketChannel.register(selector, 0);
        selectionKey.interestOps(SelectionKey.OP_ACCEPT);
        serverSocketChannel.socket().bind(new InetSocketAddress(8080));//绑定端口
        System.out.println("服务端启动");
        while (true) {
            //启动selector
            int readyChannels = selector.select();//会阻塞，直到事件通知才会返回
            if (readyChannels == 0) {
                continue;
            }
            System.out.println("触发的事件数：" + readyChannels);
            //获取被触发的事件集合
            Set<SelectionKey> selectedKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectedKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                System.out.println("key isAcceptable: " + key.isAcceptable()
                        + ", isConnectable: " + key.isConnectable()
                        + ", isReadable: " + key.isReadable()
                        + ", isWritable: " + key.isWritable()
                        + ", isValid: " + key.isValid());
                if (key.isAcceptable()) {
                    SocketChannel socketChannel = ((ServerSocketChannel) key.channel()).accept();
                    socketChannel.configureBlocking(false);
                    socketChannel.register(selector, SelectionKey.OP_READ);
                    System.out.println("收到新的客户端连接：" + socketChannel);
                } else if (key.isConnectable()) {
                    //连接到远程服务端，只在客户端异步连接时生效
                    System.out.println("客户端连接到了服务端");
                } else if (key.isReadable()) {//客户端连接有数据可以读时触发
                    //SocketChannel 中有数据可以读
                    try {
                        SocketChannel socketChannel = (SocketChannel) key.channel();
                        ByteBuffer requestBuffer = ByteBuffer.allocate(1024);
                        //read非阻塞的
                        while (socketChannel.isOpen() && socketChannel.read(requestBuffer) != -1) {
                            //长连接下，需要手动判断数据有没有读取结束(此处做一个简单的判断：超过0字节)
                            if (requestBuffer.position() > 0) break;
                        }
                        if (requestBuffer.position() == 0) continue;
                        requestBuffer.flip();//转换为读模式
                        byte[] content = new byte[requestBuffer.remaining()];
                        requestBuffer.get(content);
                        System.out.println("收到数据，来自：" + socketChannel.getRemoteAddress());
                        System.out.println(new String(content));

                        //TODO 业务操作

                        key.interestOps(SelectionKey.OP_WRITE);

                        //响应结果 200
//                        String response = "HTTP/1.1 200 OK\r\n" + "Content-Length: 11\r\n\r\n" + "Hello World";
//                        ByteBuffer buffer = ByteBuffer.wrap(response.getBytes());
//                        while (buffer.hasRemaining()) {
//                            socketChannel.write(buffer);//非阻塞
//                        }
//                        socketChannel.close();
//                        key.cancel();
                    } catch (Exception e) {
                        e.printStackTrace();
                        key.cancel();
                    }
                } else if (key.isWritable()) {
                    //SocketChannel 可以开始写入数据
                    //响应结果 200
                    SocketChannel socketChannel = (SocketChannel) key.channel();
                    String response = "HTTP/1.1 200 OK\r\n" + "Content-Length: 11\r\n\r\n" + "Hello World";
                    ByteBuffer buffer = ByteBuffer.wrap(response.getBytes());
                    while (buffer.hasRemaining()) {
                        socketChannel.write(buffer);//非阻塞
                    }
                    key.interestOps(0);
                }

                //将已处理的事件移除，否则认为没处理过，再处理一遍
                iterator.remove();
            }
//            selectedKeys.clear();
        }
    }
}
